/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2019-2019.
 * Description: hwdog common driver
 * Author: xiaowei
 * Create: 2019-07-18
 */
#include <linux/hal/watchdog.h>

#define DECOMPRESS_MAX_ADDR	0xFFFFFFFF
#define OP_MAX 16
/* why cant I use static in decompressed */
struct drol_op op_arr[OP_MAX];
int op_nr;
int feed_cnt;
static bool reg_range_ok(const void *dtb_addr, struct drol_op *op, int op_size)
{
	int i;
	/* if in kernel space, dtb_addr must be NULL */
	if (!dtb_addr)
		return true;

#ifndef CONFIG_RTOS_HAL_SELFDECOMPRESS_MAP_PHYS_ADDR_ABOVE_4G
	/*
	 * until now, we didn't support operating regs
	 * out of 4G during zImage decompressed
	 */
	for (i = 0; i < op_size; i++)
		if (op[i].reg > DECOMPRESS_MAX_ADDR)
			return false;
#endif
	return true;
}

static int hwdog_node_init(const char *name, const void *dtb_addr, bool use_fdt, drol_map map, drol_unmap unmap)
{
	int nr;
	int ret;
	drol_get_op_func get_op;

	get_op = use_fdt ? drol_get_op_fdt : drol_get_op;
	nr = get_op(op_arr, OP_MAX, name, dtb_addr);
	if (nr < 0)
		return 0;

	if (!reg_range_ok(dtb_addr, op_arr, nr))
		return -EIO;

	ret = drol_map_op(op_arr, nr, map, unmap);
	if (ret)
		return ret;

	drol_do_op(op_arr, nr);
	return nr;
}

static void hwdog_destroy(drol_unmap unmap)
{
	drol_unmap_op(op_arr, op_nr, unmap);
	op_nr = 0;
}

void hwdog_simple_init(const void *dtb_addr, bool use_fdt, drol_map map, drol_unmap unmap)
{
	op_nr = hwdog_node_init("rtos-hwdog-init", dtb_addr, use_fdt, map, unmap);
	if (op_nr < 0)
		return;

	hwdog_destroy(unmap);

	op_nr = hwdog_node_init("rtos-hwdog-feed", dtb_addr, use_fdt, map, unmap);
}

void hwdog_feed(void)
{
	drol_do_op(op_arr, op_nr);
}

void hwdog_feed_intermittent(int interval)
{
	if ((interval != 0) && (++feed_cnt % interval == 0))
		hwdog_feed();
}

#ifdef CONFIG_RTOS_HAL_SELFDECOMPRESS_MAP_PHYS_ADDR_ABOVE_4G
void unmap_hwdog_addr_above_4G(void *virt)
{
}
#endif

void hwdog_cpy_op(struct drol_op *op_addr, int *op_size_addr)
{
	memcpy(op_addr, op_arr, sizeof(struct drol_op) * OP_MAX);
	*op_size_addr = op_nr;
}
